package cn.springsoter.core.tool.utils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;

import cn.springsoter.core.tool.constant.SpringSoterConstant;
import lombok.extern.slf4j.Slf4j;

/**
 * json工具类，基于jackson封装
 * 
 * @author kevin
 *
 */
@Slf4j
public class JacksonUtil {
	
	private static ObjectMapper objectMapper = SpringUtil.getBean("objectMapper");
	
	private static final String R_CODE = "code";
	private static final String R_MESSAGE = "message";
	private static final String R_DATA = "data";
	private static final String R_LIST = "list";
	
	private JacksonUtil() {}
	
	/**
	 * 将对象sourceObject转换成Json字符串
	 * 
	 * @param sourceObject	需要转换的对象
	 * @return
	 */
	public static String toJson(Object sourceObject) {
		String jsonResult = null;
		try {
			jsonResult = objectMapper.writeValueAsString(sourceObject);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
			jsonResult = "{}";
		}
		return jsonResult;
	}

	/**
	 * 带过滤器的对象转换成String
	 * 
	 * @param filters	过滤器：把sourceObject不需要进行序列化的字段过滤掉
	 * 			具体使用参考链接：{@link https://www.logicbig.com/tutorials/misc/jackson/json-filter-annotation.html}
	 * @param sourceObject	需要转换的对象
	 * @return
	 */
	public static String toJson(FilterProvider filters, Object sourceObject) {
		String jsonResult = null;

		try {
			jsonResult = objectMapper.writer(filters).writeValueAsString(sourceObject);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
			jsonResult = "{}";
		}
		return jsonResult;
	}
	
	/**
	 * 把json字符串转换成Map<String, Object>对象
	 * 
	 * @param jsonString	需要转换的json字符串
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> toMap(String jsonString) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		if(!isValidJSON(jsonString)) {
			return resultMap;
		}
		try {
			resultMap = objectMapper.readValue(jsonString, Map.class);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return resultMap;
	}

	/**
	 * 把json字符串转换成Map<String, String>对象
	 * 
	 * @param jsonString	需要转换的json字符串
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, String> toStringMap(String jsonString) {
		Map<String, String> resultMap = new HashMap<String, String>();
		if(!isValidJSON(jsonString)) {
			return resultMap;
		}
		try {
			resultMap = objectMapper.readValue(jsonString, Map.class);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return resultMap;
	}

	/**
	 * 把json字符串转换成List<Object>对象
	 * 
	 * @param jsonString	需要转换的json字符串
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List<Object> toList(String jsonString) {
		List<Object> result = new ArrayList<Object>();
		if(!isValidJSON(jsonString)) {
			return result;
		}
		try {
			result = objectMapper.readValue(jsonString, List.class);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return result;
	}

	/**
	 * 把json字符串转换成指定Class对象集合
	 * 
	 * 	例如：List<Log> list = JacksonUtil.toList(jsonString, Log.class);
	 * 
	 * @param <T>	指定Class对象的范型
	 * @param jsonString	需要转换的json字符串
	 * @param cls	指定的Class对象
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> List<T> toList(String jsonString, Class<T> cls) {
		List<T> objList = null;
        try {
            final JavaType t = objectMapper.getTypeFactory().constructParametricType(List.class, cls);
            objList = objectMapper.readValue(jsonString, t);
        } catch (Exception e) {
        	log.error(StringUtils.EMPTY, e);
        }
        return objList;
	}

	/**
	 * 把json字符串转换成指定Class的具体Object对象
	 * 
	 * @param jsonString	需要转换的json字符串
	 * @param clazz		指定的Class对象
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Object toObject(String jsonString, @SuppressWarnings("rawtypes") Class clazz) {
		Object resultObj = new Object();
		if(!isValidJSON(jsonString)) {
			return resultObj;
		}
		try {
			resultObj = objectMapper.readValue(jsonString, clazz);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return resultObj;
	}
	
	/**
	 * 使用示例：
	 *  class Test {
	 *  	private int a;
	 *  	private int b;
	 *  
	 *  	// getter & setter method
	 *  }
	 * 	String json1 = "{\"a\":1, \"b\":2}";
	 * 	Test test = JacksonUtil.toObject(json1, new TypeReference<Test>() {});	
	 * 	
	 *  String json2 = "[{\"a\":1, \"b\":2},{\"a\":1, \"b\":2}]";
	 *  List<Test> test = JacksonUtil.toObject(json2, new TypeReference<List<Test>>() {});
	 * 
	 * @param <T>
	 * @param jsonString
	 * @param typeReference
	 * @return
	 */
	public static <T> T toObject(String jsonString, TypeReference<T> typeReference) {
		T resultObj = null;
		if(!isValidJSON(jsonString)) {
			return resultObj;
		}
		try {
			resultObj = objectMapper.readValue(jsonString, typeReference);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return resultObj;
	}
	

	/**
	 * 校验是否合法json串
	 * 
	 * @param json
	 * @return
	 */
	public static boolean isValidJSON(final String json) {
		boolean valid = false;
		try {
			if (StringUtils.isBlank(json))
				return valid;
			final JsonParser parser = objectMapper.getFactory().createParser(json);
			while (parser.nextToken() != null) {
			}
			valid = true;
		} catch (Exception e) {
		}
		return valid;
	}

	/**
	 * json字符串转化成JsonNode对象
	 * 
	 * @param json
	 * @return
	 */
	public static JsonNode toJsonNode(String json) {
		JsonNode jsonNode = objectMapper.createObjectNode();
		if(!isValidJSON(json)) {
			return jsonNode;
		}
		try {
			jsonNode = objectMapper.readValue(json, JsonNode.class);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return jsonNode;
	}
	
	/**
	 * map转化成JsonNode对象
	 * 
	 * @param map
	 * @return
	 */
	public static JsonNode toJsonNode(Map<String, Object> map) {
		JsonNode jsonNode = objectMapper.createObjectNode();
		if(MapUtils.isEmpty(map)) {
			return jsonNode;
		}
		try {
			jsonNode = objectMapper.convertValue(map, JsonNode.class);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return jsonNode;
	}
	
	/**
	 * Object转化成JsonNode对象
	 * 
	 * @param map
	 * @return
	 */
	public static JsonNode toJsonNode(Object obj) {
		JsonNode jsonNode = objectMapper.createObjectNode();
		if(Objects.isNull(obj)) {
			return jsonNode;
		}
		try {
			jsonNode = objectMapper.convertValue(obj, JsonNode.class);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return jsonNode;
	}
	
	/**
	 * 获取http调用返回的response中的"code"字段值
	 * 
	 * @param jsonNode
	 * @return	Integer
	 */
	public static Integer getCode(JsonNode jsonNode) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode codeJsonNode = jsonNode.get(R_CODE);
		return Objects.isNull(codeJsonNode) ? null : codeJsonNode.asInt();
	}
	
	/**
	 * 获取http调用返回的response中的"message"字段值，返回字符串
	 * 
	 * @param jsonNode
	 * @return	String
	 */
	public static String getMessage(JsonNode jsonNode) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode messageJsonNode = jsonNode.get(R_MESSAGE);
		return Objects.isNull(messageJsonNode) ? null : messageJsonNode.asText();
	}
	
	/**
	 * 获取http调用返回的response中的"message"字段值，并转换成JsonNode
	 * 
	 * @param jsonNode
	 * @return	JsonNode
	 */
	public static JsonNode getData(JsonNode jsonNode) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode dataJsonNode = jsonNode.get(R_DATA);
		return Objects.isNull(dataJsonNode) ? null : dataJsonNode;
	}
	
	
	/**
	 * 将jsonNode转化为java对象
	 * 
	 * @param <T>
	 * @param jsonNode
	 * @param tClass
	 * @return
	 */
	public static <T> T toJavaObject(JsonNode jsonNode, Class<T> tClass) {
		T t = null;
		if(Objects.isNull(jsonNode)) {
			return t;
		}
		try {
			t = objectMapper.convertValue(jsonNode, tClass);
		} catch (Exception e) {
			log.error(StringUtils.EMPTY, e);
		}
		return t;
	}
	
	/**
	 * 获取String类型字段
	 * 
	 * @param jsonNode	JsonNode
	 * @param fieldName	字段名
	 * @return
	 */
	public static String getString(JsonNode jsonNode, String fieldName) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode field = jsonNode.get(fieldName);
		return Objects.isNull(field) ? null : field.asText();
	}
	
	/**
	 * 获取Integer类型字段
	 * 
	 * @param jsonNode	JsonNode
	 * @param fieldName	字段名
	 * @return
	 */
	public static Integer getInteger(JsonNode jsonNode, String fieldName) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode field = jsonNode.get(fieldName);
		return Objects.isNull(field) || !NumberUtil.isInteger(field.asText()) ? null : field.asInt();
	}
	
	/**
	 * 获取Double类型字段
	 * 
	 * @param jsonNode	JsonNode
	 * @param fieldName	字段名
	 * @return
	 */
	public static Double getDouble(JsonNode jsonNode, String fieldName) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode field = jsonNode.get(fieldName);
		return Objects.isNull(field) || !NumberUtil.isDouble(field.asText()) ? null : field.asDouble();
	}
	
	/**
	 * 获取Long类型字段
	 * 
	 * @param jsonNode	JsonNode
	 * @param fieldName	字段名
	 * @return
	 */
	public static Long getLong(JsonNode jsonNode, String fieldName) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode field = jsonNode.get(fieldName);
		return Objects.isNull(field) || !NumberUtil.isLong(field.asText()) ? null : field.asLong();
	}
	
	/**
	 * 获取Boolean类型字段
	 * 
	 * @param jsonNode
	 * @param fieldName
	 * @return
	 */
	public static Boolean getBoolean(JsonNode jsonNode, String fieldName) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode field = jsonNode.get(fieldName);
		return Objects.isNull(field) ? null : field.asBoolean();
	}
	
	/**
	 * 获取Date类型字段
	 * 
	 * @param jsonNode	JsonNode
	 * @param fieldName	字段名
	 * @return
	 */
	public static Date getDate(JsonNode jsonNode, String fieldName) {
		if(Objects.isNull(jsonNode)) {
			return null;
		}
		JsonNode field = jsonNode.get(fieldName);
		return Objects.isNull(field) || !NumberUtil.isLong(field.asText()) ? null : new Date(field.asLong());
	}
	
	/**
	 * 如果某个字段是数组，则将此字段转化成list
	 * 
	 * @param <T>		
	 * @param jsonNode	JsonNode
	 * @param fieldName	字段名
	 * @param tClass	指定类
	 * @return	如果没有，返回空列表
	 */
	public static <T> List<T> getList(JsonNode jsonNode, String fieldName, Class<T> tClass) {
		List<T> results = new ArrayList<T>();
		if(Objects.isNull(jsonNode)) {
			return results;
		}
		JsonNode field = jsonNode.get(fieldName);
		if(Objects.nonNull(field) && field.isArray()) {
			for (final JsonNode objNode : field) {
				results.add(objectMapper.convertValue(objNode, tClass));
		    }
		}
		return results;
	}
	
	
	/**
	 * 获取data下的list，并转化成指定的类对象
	 * 
	 * @param <T>		
	 * @param data	JsonNode
	 * @param tClass	指定类
	 * @return	如果没有，返回空列表
	 */
	public static <T> List<T> getDataList(JsonNode data, Class<T> tClass) {
		return getList(data, R_LIST, tClass);
	}
	
	/**
	 * 获取内部接口返回的data
	 * 
	 * @param result	内部接口返回的消息，消息格式必须是：{code: 400, message: "", data: {}}
	 * @return			JsonNode
	 */
	public static JsonNode getData(String result) {
		JsonNode jsonObject = toJsonNode(result);
		JsonNode data = getData(jsonObject);
		Integer code = getCode(jsonObject);
		if (Objects.nonNull(data) && Objects.equals(code, SpringSoterConstant.ZERO)) {
			return data;
		} else {
			log.error(JacksonUtil.getMessage(jsonObject));
			return null;
		}
	}
	
	/**
	 * 判断并返回boolean值
	 * 
	 * @param result
	 * @return
	 */
	public static boolean isSuccess(String result){
		JsonNode jsonObject = toJsonNode(result);
    	Integer code = getCode(jsonObject);
        if (Objects.equals(code, SpringSoterConstant.ZERO)) {
            return true;
        } else {
        	log.error(result);
        	return false;
        }
	}
	
//	public static void main(String[] args) {
//		String message = "{\"action\":\"LinsDomainMessage\",\"data\":{\"type\":\"Created\",\"source\":\"Ticket\",\"sourceId\":\"1339821653340930050\",\"sourceType\":\"riskTicket\",\"id\":\"69e46a21-40fb-11eb-aab2-3aaea0bfd126\",\"ticketId\":\"69e46a21-40fb-11eb-aab2-3aaea0bfd126\",\"ticketNo\":\"20121814367266\",\"category\":\"internal\",\"status\":\"assigned\",\"isMain\":false,\"revision\":0,\"data\":{\"user\":{\"id\":1285781452164132900,\"mobile\":\"+8613910686019\",\"nickname\":\"郑家杰\"},\"creator\":{\"mobile\":\"+8613910686019\",\"nickname\":\"郑家杰\",\"gender\":1,\"email\":\"\",\"origin\":0,\"age\":30,\"id\":\"1285781452164132866\",\"description\":\"研发\",\"empno\":\"zhengjiajie\",\"avatar\":\"\",\"createdTime\":1595389161518,\"expiryTime\":1722355200000,\"level\":\"研发\",\"region\":{\"province\":\"\",\"city\":\"\",\"area\":\"\",\"provinceName\":\"\",\"cityName\":\"\",\"areaName\":\"\"},\"isDeleted\":0,\"roleList\":[{\"id\":\"0\",\"name\":\"超级管理员\"}],\"clientIds\":[]},\"title\":\"语文学习方法之二\"}},\"timestamp\":1608273412438,\"msgId\":\"6a018f5d-40fb-11eb-aab2-3aaea0bfd126\",\"traceId\":\"6a01900f-40fb-11eb-aab2-3aaea0bfd126\",\"key\":\"69e46a21-40fb-11eb-aab2-3aaea0bfd126\"}";
//		
//		JsonNode jsonNode = JSONUtil.toJsonNode(message);
//    	JsonNode data = JSONUtil.getData(jsonNode);
//        if(Objects.nonNull(data) && data.has("data")){
//            
//        }
//	}
}
